﻿#pragma once
#if defined(_MSC_VER)
	#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iostream>

class MyString {
public:
	MyString() = default; // 默认构造函数
	MyString(const char*&& str) noexcept { // 构造函数，noexcept 表示不会抛出异常，可以避免移动构造函数的调用
		if (str) {
			m_len = strlen(str);
			m_str = new char[m_len]; // 为字符串分配内存，注意语法，注意 new 分配小内存是在栈上分配
			memcpy(m_str, str, m_len);
			printf("initialized constructor successfully\n");
		}
		else {
			m_len = 0;
			m_str = nullptr;
			printf("null pointer constructor created \n");
		}
	}
	MyString(const MyString& other) { // 拷贝构造函数
		m_len = other.m_len;
		m_str = new char[m_len];
		memcpy(m_str, other.m_str, m_len);
		printf("copy constructor called\n");
	}
	MyString(MyString&& other) noexcept { // 移动构造函数，
		m_len = other.m_len;
		m_str = other.m_str;
		other.m_str = nullptr; // 移动语义，将 other 的指针置空，避免释放两次内存
		other.m_len = 0;
		printf("move constructor called\n");
	}

	~MyString() { // 析构函数
		if (m_str) {
			delete m_str;
			m_str = nullptr;
			printf("destructor string called\n");
		}
		else
			printf("null pointer destructor called\n");
	}

	MyString& operator=(const MyString& other) { // 赋值运算符
		if (this != &other) {
			delete m_str;
			m_len = other.m_len;  // 传入参数为类时，可以直接右值访问引用对象的私有成员变量
			m_str = new char[m_len]; // 为字符串分配内存
			memcpy(m_str, other.m_str, m_len);
			printf("other string assignment operator called\n");
		}
		return *this;
	}

	MyString& operator=(MyString&& other) noexcept { // 移动赋值运算符
		if (!other.m_str)
			printf("null pointer move assignment operator called, do nothing\n");
		else if (this != &other) {
			delete m_str;
			m_len = other.m_len;  // 在重载操作符函数中，可以直接访问引用对象的私有成员变量
			m_str = other.m_str; // 移动语义，将 other 的指针赋值给 this 的指针
			memcpy(m_str, other.m_str, m_len);
			other.m_str = nullptr; // 移动语义，将 other 的指针置空，避免释放两次内存
			other.m_len = 0;
			printf("move string assignment operator successfully\n");
		}
		return *this;
	}

	MyString& operator+(const MyString& other) { // 字符串赋值运算符
		if (other.m_str)
		{
			if (!m_str) {
				m_str = new char[other.m_len];
				m_len = other.m_len;
				memcpy(m_str, other.m_str, m_len);
				printf("string addition operator called\n");
			}
			else {
				char* new_str = (char*)realloc(m_str, m_len + other.m_len);
				if (new_str) {
					char* temp = m_str;
					m_str = new_str;
					memcpy(m_str, temp, m_len);
					memcpy(m_str + m_len, other.m_str, other.m_len);
					m_len += other.m_len;
					printf("tow string concatenation operator called\n");
				}
				else
					printf("memory allocation failed\n");
			}
		}
		else
			printf("string is not added\n");
		return *this;
	}

	MyString& operator=(const char*&& other) noexcept { // 常量字符串赋值运算符，常量右值引用（C++11 特性）
		if (other) {
			m_len = strlen(other);
			m_str = new char[m_len];
			memcpy(m_str, other, m_len);
			printf("constant string assignment operator called\n");
		}
		else {
			m_len = 0;
			m_str = nullptr;
			printf("null pointer assignment operator called\n");
		}
		return *this;
	}

	MyString& operator+(const char*&& other) noexcept { // 字符串连接运算符
		if (other) {
			size_t other_len = strlen(other);
			if (!m_str) {
				m_str = new char[other_len];
				m_len = other_len;
				memcpy(m_str, other, other_len);
			}
			else {
				char* new_str = (char*)realloc(m_str, m_len + other_len); // realloc 重新分配内存，避免内存碎片，会自动释放之前 m_str 的内存
				if (new_str) {
					char* temp = m_str;
					m_str = new_str;
					memcpy(m_str, temp, m_len);
					memcpy(m_str + m_len, other, other_len);
					m_len += other_len;
					printf("string concatenation operator called\n");
				}
				else
					printf("memory allocation failed\n");
			}
		}
		else
			printf("string is not added\n");
		return *this;
	}

	void print_str() { // 打印字符串内容
		if (m_str) {
			for (size_t i = 0; i < m_len; i++)
				putchar(m_str[i]);
			putchar('\n');
		}
		else
			printf("null pointer string\n");
	}
private:
	char* m_str; // 字符串内容
	size_t m_len; // 字符串长度
};

extern void test_move_semantics(); // 测试移动语义

extern void test_constexpr_inline(); // 测试 constexpr inline 关键字


// 宏定义
#define print_start(str) std::cout << " ----------------- " << str << " Start ------------------------\n";
#define print_end(str) std::cout << " ----------------- " << str << " End ------------------------\n\n\n";